package mygate

import (
	"encoding/binary"
	"io"
	"runtime"
	"sync"

	"github.com/name5566/leaf/log"
	"github.com/name5566/leaf/network"
)

func init() {
	G_allConn = make(ConnSet)
}

func NewMyGateNode(conn *network.TCPConn) *MyGateNode {
	t := &MyGateNode{conn: conn}
	t.uid = G_uidIndex
	G_connLock.Lock()
	defer G_connLock.Unlock()
	G_allConn[G_uidIndex] = t
	G_uidIndex++
	return t
}

const maxBufLen = 10240
const defaultBufLen = 1024
const headLen = 6
const lenStackBuf = 1024

type MyGateNode struct {
	uid  uint32
	conn *network.TCPConn
}
type ConnSet map[uint32]*MyGateNode

var G_connLock sync.Mutex
var G_allConn ConnSet
var G_uidIndex uint32

func (a *MyGateNode) Run() {
	defer func() {
		a.conn.Destroy()
		if r := recover(); r != nil {
			if lenStackBuf > 0 {
				buf := make([]byte, lenStackBuf)
				l := runtime.Stack(buf, false)
				log.Release("%v: %s\n", r, buf[:l])
			} else {
				log.Release("%v\n", r)
			}
		}
	}()

	var msgLen uint32
	var msgID uint16
	var b [defaultBufLen]byte
	bufMsgHead := b[:headLen]
	bufMsgLen := b[:4]
	bufMsgID := b[4:6]
	for {
		if _, err := io.ReadFull(a.conn, bufMsgHead); err != nil {
			return
		}
		msgLen = binary.LittleEndian.Uint32(bufMsgLen)
		msgID = binary.LittleEndian.Uint16(bufMsgID)

		if msgLen > maxBufLen {
			log.Release("read msg len = %v, id = %v\n", msgLen, msgID)
			return
		}

		if msgLen > 0 {
			var msgData []byte
			var sendData []byte
			//				msgData := make([]byte, msgLen)
			if msgLen <= defaultBufLen {
				msgData = b[headLen:msgLen]
				sendData = b[:msgLen]
			} else {
				tBuf := make([]byte, headLen+msgLen)
				copy(tBuf, b[:headLen])
				msgData = tBuf[headLen:msgLen]
				sendData = tBuf[:msgLen]
			}

			if _, err := io.ReadFull(a.conn, msgData); err != nil {
				return
			}
			log.Debug("read msg len = %v, id = %v, data = %v\n", msgLen, msgID, string(msgData))

			// broadcast to all connect node
			broadcast_data(sendData)
		}
	}
}

func broadcast_data(sendData []byte) {
	G_connLock.Lock()
	defer G_connLock.Unlock()

	for k_, v_ := range G_allConn {
		log.Debug("send msg to %v\n", k_)
		v_.conn.Write(sendData)
	}
}

func (a *MyGateNode) OnClose() {
	log.Release("%v closed\n", a.uid)
	G_connLock.Lock()
	defer G_connLock.Unlock()
	delete(G_allConn, a.uid)
	// if a.gate.AgentChanRPC != nil {
	// 	err := a.gate.AgentChanRPC.Call0("CloseAgent", a)
	// 	if err != nil {
	// 		log.Error("chanrpc error: %v", err)
	// 	}
	// }
}
